package ;
import StringBuf;
import Main;
import HLlr;
import HLex;








class Writer {
    static inline function addStr(buf:StringBuf,x:String) {
        buf.addSub(x,0,x.length);
    }
    
    public static inline function print(x:MFile, ?debug=false) {
        buf = new StringBuf();
        pre = false;
        nl = false;
        
        addStr(buf,"package "+x.packages+";\n");
        for(i in x.imports)
            addStr(buf,"import "+i.importname+";\n");
        
        for(i in x.scope.data)
            xprint(i,debug,"");
            
        if(nl) buf.addChar(NL);
        
        return buf.toString();
    }
	
	public static inline function printstates(x:Array<State>) {
		buf = new StringBuf();
        pre = false;
        nl = false;
        
        for(i in x)
            xprint(i,true,"");
            
        return buf.toString();
    }
    
    static var NL = '\n'.charCodeAt(0);
    static var SPACE = ' '.charCodeAt(0);
    
    static inline function scopeof(scope:MacroScope) {
        if(scope!=null) {
            addStr(buf,switch(scope) {
                case sLocal: "local ";
                case sGlobal: "global ";
                case sFile:   "file ";
                case sObject: "object ";
                case sMethod: "method ";
            });
        }   
    }
    
    static var pre:Bool;
    static var nl:Bool;
    static var buf:StringBuf;
    static function xprint(x:State, debug:Bool, tab:String) {
        if(tab==null) tab = "";
        switch(x) {
            case sCons:
                addStr(buf,"`");
                nl = pre = false;
            case sMImport(x):
                if(debug) {
                    if(nl) { buf.addChar(NL); addStr(buf,tab); }
                    addStr(buf,"//$(import "+x+")");
                    addStr(buf,';');
                    nl = true;
                    pre = false;
                }
            case sImport(x):
                if(debug) {
                    if(nl) { buf.addChar(NL); addStr(buf,tab); }
                    addStr(buf,"//import "+x+";");
                    nl = true;
                    pre = false;
                }
            case sNoise(x):
                if(nl) { buf.addChar(NL); addStr(buf,tab); };
                addStr(buf,x);
                if(x.charAt(x.length-1)==';') nl = true;
                else nl = false;
                pre = false;
            case sIdent(x):
                if(nl) { buf.addChar(NL); addStr(buf,tab); }
                if(pre && !nl) buf.addChar(SPACE);
                nl = false;
                addStr(buf,x);
                pre = true;
            case sDatum(x):
                if(nl) { buf.addChar(NL); addStr(buf,tab); }
                if(pre && !nl) buf.addChar(SPACE);
                nl = false;
                addStr(buf,x);
                pre = true;
            case sInteger(x):
                if(nl) { buf.addChar(NL); addStr(buf,tab); }
                if(pre && !nl) buf.addChar(SPACE);
                nl = false;
                addStr(buf,x);
                pre = true;
            case sRealScope(xs):
                if(nl) { buf.addChar(NL); addStr(buf,tab); }
                addStr(buf,'{'); if(debug) addStr(buf,'#'+xs.id);
                nl = true;
                pre = false;
                if(xs.data.length==0) addStr(buf,'}');
                else {
                    for(x in xs.data) xprint(x,debug,tab+'\t');
                    buf.addChar(NL); addStr(buf,tab);
                    addStr(buf,'}');
                }
                pre = false;
                nl = true;
            case sCall(args):
                if(nl) { buf.addChar(NL); addStr(buf,tab); }
                addStr(buf,'(');
                pre = false;
                nl = false;
                for(i in args) {
                    if(i!=args[0]) { addStr(buf,','); pre = false; }
                    for(x in i) xprint(x,debug,tab);
                }
                
                addStr(buf,')');
                nl = pre = false;
                
            case sArgument(macro,cnt):
                if(nl) { buf.addChar(NL); addStr(buf,tab); }
                addStr(buf,macro+'&'+cnt);
                pre = false;
                nl = false;
                
            case sMixin(scope,x,args,xs,mac):
                if(debug) {
                    if(nl) { buf.addChar(NL); addStr(buf,tab); }
                    addStr(buf,"$"+mac.id+"(mixin ");
                    scopeof(scope);
                    addStr(buf,x+'(');
                    for(i in args) {
                        if(i!=args[0]) addStr(buf,',');
                        addStr(buf,i);
                    }
                    addStr(buf,') ');
                    pre = nl = false;
                    for(x in xs) xprint(x,debug,tab);
                    addStr(buf,');');
                    pre = false;
                    nl = true;
                }
                
            case sExpand(scope,x,args,xs,mac):
                if(debug) {
                    if(nl) { buf.addChar(NL); addStr(buf,tab); }
                    addStr(buf,"$"+mac.id+"(expand ");
                    scopeof(scope);
                    addStr(buf,x+'(');
                    for(i in args) {
                        if(i!=args[0]) addStr(buf,',');
                        addStr(buf,i);
                    }
                    addStr(buf,') ');
                    pre = nl = false;
                    for(x in xs) xprint(x,debug,tab);
                    addStr(buf,');');
                    pre = false;
                    nl = true;
                }
				for(i in mac.instances) {
					for(x in i) xprint(x,debug,tab);
				}
                
            case sDefine(scope,newfile,preamble,x,args,xs,mac):
                if(debug) {
                    if(nl) { buf.addChar(NL); addStr(buf,tab); }
                    addStr(buf,"$"+mac.id+"(define ");
                    scopeof(scope);
                    if(newfile) addStr(buf,'newfile ');
                    pre = nl = false;
                    for(i in preamble)
                        xprint(i,debug,tab);
                    if(nl) { buf.addChar(NL); addStr(buf,tab); }
                    buf.addChar(SPACE);
                    addStr(buf,x+'(');
                    for(i in args) {
                        if(i!=args[0]) addStr(buf,',');
                        addStr(buf,i);
                    }
                    addStr(buf,') ');
                    pre = nl = false;
                    for(x in xs) xprint(x,debug,tab);
                    addStr(buf,');');
                    pre = false;
                    nl = true;
                }
				for(i in mac.instances) {
					for(x in i) xprint(x,debug,tab);
				}
				
            default:
        }
    }
}

